// created Jan 9, 2009 11:12:26 AM
// by petrovic
/*
Copyright 2009 Homosuperiorus LLC 

Licensed under the Apache License, Version 2.0 (the "License"); you may not use 
this file except in compliance with the License.  You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0 

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied. See the License for the specific language governing
permissions and limitations under the License.

*/

package org.taglets.pub.tags;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public final class Tag {
    private static Logger LOG = Logger.getLogger(Tag.class.getName());

    private String name;
    private String description;
    private String created;
    private boolean following;
    private int nComment;
    private int nFollowers;
    private boolean isOwner;
    private ArrayList<Outlet> outlets;

    public Tag(String name, String description, String created, String following, String nComment, String isOwner) {
        this.name = name;
        this.description = description;
        this.created = created;
        this.following = following.equals("true");
        this.isOwner = isOwner.equals("true");
        this.nComment = Integer.parseInt(nComment);
    }

    public Tag(String name, String description, String created, int nFollowers, String nComment) {
        this.name = name;
        this.description = description;
        this.created = created;
        this.nFollowers = nFollowers;
        this.nComment = Integer.parseInt(nComment);
    }

    public static Tag buildFollowedTag(InputStream is) throws IOException {
        List<Tag> tagList = Tag.buildTagList(is, false);
        return tagList.get(0);
    }

    public static List<Tag> buildTagList(InputStream is, boolean multipleTags) throws IOException {
        List<Tag> tagList = new ArrayList<Tag>();
        try {
            DocumentBuilder builder;
            builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            Document document = builder.parse(is);
            XPath xpath = XPathFactory.newInstance().newXPath();

            // XXX: god awful hack to signal multiple tags in a response
            String prefix = multipleTags ? "/tags/tag" : "/tag";

            NodeList tagNodeList = (NodeList) xpath.evaluate(prefix, document, XPathConstants.NODESET);
            for (int i = 0; i < tagNodeList.getLength(); ++i) {
                Element tagElement = (Element) tagNodeList.item(i);
                String name = xpath.evaluate("@name", tagElement);
                String description = xpath.evaluate("@description", tagElement);
                String created = xpath.evaluate("@created", tagElement);
                String following = xpath.evaluate("@following", tagElement);
                String nComment = xpath.evaluate("@ncomment", tagElement);
                String isOwner = xpath.evaluate("@isowner", tagElement);

                Tag tag = new Tag(name, description, created, following, nComment, isOwner);

                ArrayList<Outlet> outlets = new ArrayList<Outlet>();
                NodeList nodeList = (NodeList) xpath.evaluate("/tag/outlet", tagElement, XPathConstants.NODESET);
                for (int k = 0; k < nodeList.getLength(); ++k) {
                    Element outletElement = (Element) nodeList.item(k);
                    String uri = xpath.evaluate("@uri", outletElement);
                    String protocol = xpath.evaluate("@protocol", outletElement);
                    Outlet o = new Outlet(uri, protocol);
                    outlets.add(o);
                }
                tag.setOutlets(outlets);
                tagList.add(tag);
            }
        } catch (ParserConfigurationException e) {
            LOG.log(Level.SEVERE, "Parsing error", e);
        } catch (SAXException e) {
            LOG.log(Level.SEVERE, "Parsing error", e);
        } catch (XPathExpressionException e) {
            LOG.log(Level.SEVERE, "Parsing error", e);
        }
        return tagList;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getCreated() {
        return created;
    }

    public void setCreated(String created) {
        this.created = created;
    }

    public boolean isFollowing() {
        return following;
    }

    public int getNFollowers() {
        return nFollowers;
    }

    public void setNFollowers(int followers) {
        nFollowers = followers;
    }

    public void setFollowing(boolean following) {
        this.following = following;
    }

    public int getNComment() {
        return nComment;
    }

    public void setNComment(int comment) {
        nComment = comment;
    }

    public ArrayList<Outlet> getOutlets() {
        return outlets;
    }

    public void setOutlets(ArrayList<Outlet> outlets) {
        this.outlets = outlets;
    }

    public boolean isOwner() {
        return isOwner;
    }

    public void setOwner(boolean isOwner) {
        this.isOwner = isOwner;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(name).append(", ").append(description).append(", ").append(created).append(", following: ").append(following).append(", owner: ").append(isOwner);
        return sb.toString();
    }
}
